package internal

import (
	"context"
	"github.com/go-redis/redis/v8"
	"math"
	"order_srv/basic/config"
	"time"
)

type DriverBrief struct {
	Id         uint32
	Lat        float64
	Lng        float64
	Rating     float64
	AcceptRate float64
}

// QueryNearbyDrivers 通过 Redis GEO 查询城市候选池
func QueryNearbyDrivers(ctx context.Context, cityId uint32, lng, lat float64, radiusKm float64) ([]DriverBrief, error) {
	key := geoKey(cityId)
	// 如果没有 GEO 数据，返回空列表即可，调用方可降级
	res, err := config.Rdb.GeoRadius(ctx, key, lng, lat, &redis.GeoRadiusQuery{
		Radius:    radiusKm,
		Unit:      "km",
		WithCoord: true,
		Sort:      "ASC",
		Count:     100,
	}).Result()
	if err != nil {
		return []DriverBrief{}, nil
	}
	list := make([]DriverBrief, 0, len(res))
	for _, v := range res {
		list = append(list, DriverBrief{
			Id:         parseUint32(v.Name),
			Lat:        v.Latitude,
			Lng:        v.Longitude,
			Rating:     4.8,  // 可从缓存/DB补充
			AcceptRate: 0.85, // 可从缓存/DB补充
		})
	}
	return list, nil
}

func geoKey(cityId uint32) string { return "geo:drivers:" + itoa(cityId) }

func itoa(u uint32) string { return fmtUint(uint64(u)) }

// 轻量无反射 itoa
func fmtUint(u uint64) string {
	if u == 0 {
		return "0"
	}
	buf := make([]byte, 0, 20)
	for u > 0 {
		buf = append(buf, byte('0'+u%10))
		u /= 10
	}
	// reverse
	for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
		buf[i], buf[j] = buf[j], buf[i]
	}
	return string(buf)
}

// HaversineKM 计算两经纬度之间的球面距离
func HaversineKM(lon1, lat1, lon2, lat2 float64) float64 {
	const R = 6371.0
	dLat := (lat2 - lat1) * math.Pi / 180
	dLon := (lon2 - lon1) * math.Pi / 180
	a := math.Sin(dLat/2)*math.Sin(dLat/2) + math.Cos(lat1*math.Pi/180)*math.Cos(lat2*math.Pi/180)*math.Sin(dLon/2)*math.Sin(dLon/2)
	c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
	return R * c
}

// IsDriverAvailable 时间窗可用性校验（可接 DB/缓存，此处占位 true）
func IsDriverAvailable(ctx context.Context, driverId uint32, from, to time.Time) bool {
	return true
}

// parseUint32 将字符串 id 转为 uint32，失败返回 0
func parseUint32(s string) uint32 {
	var n uint64
	for i := 0; i < len(s); i++ {
		c := s[i]
		if c < '0' || c > '9' {
			return 0
		}
		n = n*10 + uint64(c-'0')
	}
	if n > math.MaxUint32 {
		return 0
	}
	return uint32(n)
}
